﻿using Windows.Globalization.NumberFormatting;
using DimensionsHelper.Common.Contracts.TableFormatter.Options;
using DimensionsHelper.Common.Contracts.Excel;
using Microsoft.UI.Xaml.Hosting;
using Microsoft.UI.Xaml.Input;

namespace DimensionsHelper.Client.WinUi.Views;

public sealed partial class TableFormatterTableOptionsPage : Page
{
    private static readonly string[] SuitableNumberFormatArray =
    [
        "general",
        "0",
        "0.00",
        "#,##0",
        "#,##0.00",
        "_ * #,##0_ ;_ * -#,##0_ ;_ * \"-\"_ ;_ @_ ",
        "_ * #,##0.00_ ;_ * -#,##0.00_ ;_ * \"-\"??_ ;_ @_ ",
        "_ ¥* #,##0_ ;_ ¥* -#,##0_ ;_ ¥* \"-\"_ ;_ @_ ",
        "_ ¥* #,##0.00_ ;_ ¥* -#,##0.00_ ;_ ¥* \"-\"??_ ;_ @_ ",
        "#,##0;-#,##0",
        "#,##0;[Red]-#,##0",
        "#,##0.00;-#,##0.00",
        "#,##0.00;[Red]-#,##0.00",
        "¥#,##0;¥-#,##0",
        "¥#,##0;[Red]¥-#,##0",
        "¥#,##0.00;¥-#,##0.00",
        "¥#,##0.00;[Red]¥-#,##0.00",
        "0%",
        "0.00%",
        "0.00E+00",
        "##0.0E+0",
        "# ?/?",
        "# ??/??",
        "$#,##0_);($#,##0)",
        "$#,##0_);[Red]($#,##0)",
        "$#,##0.00_);($#,##0.00)",
        "$#,##0.00_);[Red]($#,##0.00)",
        "yyyy\"年\"m\"月\"",
        "m\"月\"d\"日\"",
        "yyyy/m/d",
        "yyyy\"年\"m\"月\"d\"日\"",
        "m/d/yy",
        "d-mmm-yy",
        "d-mmm",
        "mmm-yy",
        "h:mm AM/PM",
        "h:mm:ss AM/PM",
        "h:mm",
        "h:mm:ss",
        "h\"时\"mm\"分\"",
        "h\"时\"mm\"分\"ss\"秒\"",
        "上午/下午h\"时\"mm\"分\"",
        "上午/下午h\"时\"mm\"分\"ss\"秒\"",
        "yyyy/m/d h:mm",
        "mm:ss",
        "mm:ss.0",
        "@",
        "[h]:mm:ss",
        "yyyy\"年\"m\"月\"d\"日\""
    ];


    private static readonly DecimalFormatter IntegerFormatter = new()
    {
        IntegerDigits = 1,
        FractionDigits = 0,
        IsDecimalPointAlwaysDisplayed = false,
        NumberRounder = new IncrementNumberRounder
        {
            Increment = 1,
            RoundingAlgorithm = RoundingAlgorithm.RoundHalfUp
        }
    };

    private static readonly string[] SigBoundaryTypes =
        TypeHelper.ReadEnumMembersDescription<SigGapBoundaryType>().Keys.ToArray();


    private readonly List<CompositionSpriteShape> _borderLineShapes = [];

    private readonly TextBlock[] _hyperlinkTextBlocks;


    private bool _updatingInternal;


    public TableFormatterTableOptionsPage()
    {
        ViewModel = App.GetService<TableFormatterTableOptionsViewModel>();
        InitializeComponent();
        InitializeBorderStyle();

        // 异步读取字体列表
        Task.Run(() =>
        {
            DispatcherQueue.TryEnqueue(() => FontFamilyComboBox.ItemsSource = FontHelper.SystemFontFamilies);
        });

        FontSizeNumberBox.NumberFormatter = new DecimalFormatter
        {
            FractionDigits = 1,
            IntegerDigits = 1,
            SignificantDigits = 1,
            NumberRounder = new IncrementNumberRounder
            {
                Increment = 0.1,
                RoundingAlgorithm = RoundingAlgorithm.RoundHalfUp
            }
        };

        NumberFormatAutoSuggestBox.ItemsSource = SuitableNumberFormatArray;

        IntervalRowsNumberBox.NumberFormatter = IntegerFormatter;
        MaxEmptyRowsNumberBox.NumberFormatter = IntegerFormatter;
        TitleOffsetNumberBox.NumberFormatter = IntegerFormatter;

        _hyperlinkTextBlocks =
        [
            MenuSheetLabelTextBlock,
            MenuTableLabelTextBlock1,
            MenuTableLabelTextBlock2,
            MenuTableLabelTextBlock3,
            MenuTableLabelTextBlock4
        ];

        SigBoundaryTypeComboBox.ItemsSource = SigBoundaryTypes;
        SigBoundaryTypeComboBox.SelectedIndex = (int)ViewModel.SigBoundaryType;
        SigBoundaryTypeComboBox.SelectionChanged += SigBoundaryTypeComboBox_SelectionChanged;

        ViewModel.PropertyChanged += ViewModel_PropertyChanged;
        BorderStyleAppBarButton.RegisterPropertyChangedCallback(ForegroundProperty,
            OnBorderStyleAppButtonForegroundChanged);
    }

    public TableFormatterTableOptionsViewModel ViewModel
    {
        get;
    }


    private void OnBorderStyleAppButtonForegroundChanged(DependencyObject sender, DependencyProperty dp) =>
        UpdateBorderLineShapesStrokeBrush();


    private void UpdateBorderLineShapesStrokeBrush()
    {
        Compositor compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
        Color color = ((SolidColorBrush)BorderStyleAppBarButton.Foreground).Color;
        CompositionColorBrush brush = compositor.CreateColorBrush(color);
        foreach (CompositionSpriteShape shape in _borderLineShapes)
        {
            shape.StrokeBrush = brush;
        }
    }


    private void InitializeBorderStyle()
    {
        MenuFlyout flyout = new();
        Compositor compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;

        foreach (BorderLineInfo info in BorderHelper.LineStyles)
        {
            // 添加Radiobutton
            RadioMenuFlyoutItem item = new()
            {
                GroupName = "MenuBorderStyles",
                Width = 100
            };

            ToolTipService.SetToolTip(item, info.Label);

            if (info.Style == BorderStyle.Thin)
            {
                item.IsChecked = true;
            }

            item.Click += (_, _) =>
            {
                if (item.IsChecked)
                {
                    ViewModel.CurrentStyle.BorderStyle = info.Style;
                }
            };

            ShapeVisual visual = compositor.CreateShapeVisual();
            CompositionLineGeometry line = compositor.CreateLineGeometry();
            CompositionSpriteShape shape = compositor.CreateSpriteShape(line);
            _borderLineShapes.Add(shape);

            visual.Size = new Vector2(100, 20);

            // Start / End
            line.Start = new Vector2(32, 16);
            line.End = new Vector2(90, 16);

            // Thicknesses
            shape.StrokeThickness = (float)info.Thickness;

            // DashArray
            shape.StrokeDashArray.Clear();
            foreach (double d in info.DashArray)
            {
                shape.StrokeDashArray.Add((float)d);
            }

            visual.Shapes.Add(shape);
            ElementCompositionPreview.SetElementChildVisual(item, visual);

            flyout.Items.Add(item);
        }

        BorderStyleAppBarButton.Flyout = flyout;
        UpdateBorderLineShapesStrokeBrush();
    }


    private void ViewModel_PropertyChanged(object? sender, PropertyChangedEventArgs e)
    {
        if (_updatingInternal)
        {
            return;
        }

        if (e.PropertyName == nameof(TableFormatterTableOptionsViewModel.SigBoundaryType))
        {
            _updatingInternal = true;
            SigBoundaryTypeComboBox.SelectedIndex = (int)ViewModel.SigBoundaryType;
            _updatingInternal = false;
        }
    }

    private void SigBoundaryTypeComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (_updatingInternal)
        {
            return;
        }

        _updatingInternal = true;
        ViewModel.SigBoundaryType = (SigGapBoundaryType)SigBoundaryTypeComboBox.SelectedIndex;
        _updatingInternal = false;
    }


    private void SetHyperlinkTextBlocksInformation(bool addInformation)
    {
        foreach (TextBlock block in _hyperlinkTextBlocks)
        {
            if (addInformation)
            {
                block.PointerReleased += HyperlinkText_PointerReleased;
                block.SetValue(ToolTipService.ToolTipProperty, "超链接文本");
            }
            else
            {
                block.PointerReleased -= HyperlinkText_PointerReleased;
                block.ClearValue(ToolTipService.ToolTipProperty);
            }
        }
    }


    private void HyperlinkText_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.Hyperlink);

    private void TitleCell_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.Title);

    private void TableGrid_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.Global);

    private void HeaderRnage_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.Header);

    private void SigColumnCharacterRange_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.SigColumnCharacter);

    private void SectionMemberCell_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.SectionMember);

    private void SectionLabelCell_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.Section);

    private void BaseLabelCell_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.BaseLabel);

    private void BaseValueRange_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.BaseValue);

    private void SideRange_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.Side);

    private void InnerTextCell_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.InnerText);

    private void DataRange_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.Data);

    private void SigResult_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.SigResult);

    private void LowerCaseSigCharacter_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.LowerCaseSigCharacter);

    private void UpperCaseSigCharacter_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.UpperCaseSigCharacter);

    private void LinkSheetLabelCell_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuLinkSheetLabel);

    private void LinkSheetSheetNameRange_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuLinkSheetSheetName);

    private void MenuLinkSheetGrid_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuLinkSheetGobal);

    private void MenuGrid_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuGlobal);

    private void MenuTableNumberRange_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuTableNumber);

    private void MenuBackTextCell_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuBackText);

    private void MenuBaseRange_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuBaseLabel);

    private void MenuTableLabelRange_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuTableLabel);

    private void MenuSheetName_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuSheetLabel);

    private void MenuSectionRange_PointerReleased(object sender, PointerRoutedEventArgs e) =>
        ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuSection);

    private void MenuHideTableNumberToggleButton_Checked(object sender, RoutedEventArgs e) =>
        SetHyperlinkTextBlocksInformation(true);

    private void MenuHideTableNumberToggleButton_Unchecked(object sender, RoutedEventArgs e) =>
        SetHyperlinkTextBlocksInformation(false);

    private void MainTabView_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (e.AddedItems is not [TabViewItem item, ..])
        {
            return;
        }

        int index = MainTabView.TabItems.IndexOf(item);
        switch (index)
        {
            case 0:
                ViewModel.SetCurrentStyleRange(TableRangeLocations.Global);
                TableGrid.RefreshBorder();
                break;
            case 1:
                ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuLinkSheetGobal);
                LinkSheetBorderGrid.RefreshBorder();
                break;
            case 2:
                ViewModel.SetCurrentStyleRange(TableRangeLocations.MenuGlobal);
                IndexSheetBorderGrid.RefreshBorder();
                break;
        }
    }
}